﻿#ifdef _MSC_VER
#ifdef USE_VLD_CHECK_LEAK
#include "vld.h"
#endif
#endif

#include "proxy_service.h"

#include <thread>
#include <chrono>

#include "../../3rd/libjson/json.h"
#include "../share/GameHostManager.h"
#include "../share/MessageDef.h"
#include "world_proxy_client.h"
#include "platform_proxy_client.h"

#ifdef _MSC_VER
char * g_dump_exe_name = "ProxyServer";
#endif

CProxyService::CProxyService()
{
}

CProxyService::~CProxyService()
{

}

int32_t CProxyService::Initialize(void)
{
	int16_t listen_prot = GameHostManager::GetInstance().GetProxyHostListenPort();
	proxy_net_.Initialize(1024 * 100, 1024 * 100);
	proxy_net_.Startup(listen_prot);

	CWorldProxyClient::GetInstance().InitializeServer(GetServiceType(), GetServiceID());
	CWorldProxyClient::GetInstance().Initialize(1024 * 100, 1024 * 100);
	CPlatformProxyClient::GetInstance().InitializeServer(GetServiceType(), GetServiceID());
	CPlatformProxyClient::GetInstance().Initialize(1024 * 100, 1024 * 100);
	return 0;
}

int32_t CProxyService::Finalize()
{
	return 0;
}

bool CProxyService::AddProxyChannel(uint32_t service_type, uint32_t service_id, CProxyChannel* channel)
{
	LOG_INFO("default","service[%u][%u] is up", service_type, service_id);
	CProxyChannel* old_channel = channel_map_[service_type][service_id];
	if ( old_channel != NULL )
	{
		delete old_channel;
		old_channel = NULL;
	}
	channel_map_[service_type][service_id] = channel;
	return true;
}

CProxyChannel* CProxyService::GetProxyChannel(uint32_t service_type, uint32_t service_id)
{
	TChannelMap::iterator iter_type = channel_map_.find(service_type);
	if (iter_type != channel_map_.end())
	{
		TIDChannelMap& id_channel_map = iter_type->second;
		TIDChannelMap::iterator iter_id = id_channel_map.find(service_id);
		if (iter_id != id_channel_map.end())
		{
			return iter_id->second;
		}
	}
	return NULL;
}

int32_t CProxyService::client_msg_dispatch(std::string& msg, unsigned long uid, ::common::CProxyHead& head)
{
	CProxyNetChannel* net_channel = proxy_net_.GetChannel(uid);
	if (net_channel == NULL) {

		return -1;
	}

	// msg 已经组织好了head
	//::common::CProxyHead proxy_head;
	::common::CNetMsgTransfer::out_tcp_for_proxy(*net_channel, head, msg.c_str(), msg.size());
	//::common::CNetMsgTransfer::out_tcp_for_client(*net_channel,uid, msgId, msg.c_str(), msg.length());
	return 0;
}

int32_t CProxyService::AddClientMsg(uint32_t socketId, uint32_t msgId, std::string &msg)
{
	std::string _msg_str(msg);

	uint32_t headlen = (uint32_t)(ntohl(*(TY_MSG_HEAD_TYPE*)_msg_str.c_str()));

	std::string _msg_head_str;
	_msg_head_str.assign(_msg_str, TY_MSG_HEAD_LEN, headlen);
	::common::CProxyHead head;
	head.ReadFromString(_msg_head_str);

	// 	std::string _msg_content_str;
	// 	int32_t extend_len = ST_ASIO_HEAD_LEN + ST_ASIO_HEAD_LEN + headLen;
	// 	_msg_content_str.assign(_msg_str, extend_len, _msg_str.size() - extend_len);

	CProxySocketMsg proxy_socket_msg;
	proxy_socket_msg.SetMsg(head, _msg_str, socketId);

	AddServerMsgPtr(proxy_socket_msg);
	return 0;
}

int32_t CProxyService::AddServerMsg(uint32_t msgId, std::string &msg, const common::CProxyHead& head)
{
	return 0;
}

void CProxyService::del_client_socket(uint32_t fd)
{
	LOG_ERROR("default","fd[%d] disconnect!", fd);
	for (TChannelMap::iterator it = channel_map_.begin(); it != channel_map_.end(); ++it )
	{
		for (TIDChannelMap::iterator iter = it->second.begin(); iter != it->second.end(); ++iter )
		{
			CProxyChannel* channel = iter->second;
			if (channel == NULL)
			{
				continue;
			}
			if (channel->fd() == fd)
			{
				LOG_ERROR("default","%s disconnect proxy!", server_name_map_[channel->service_type()].c_str());
				return;
			}
		}
	}
}

void CProxyService::ProcessServerMsg(CProxySocketMsg& val)
{
	::common::CProxyHead& head = val.head_;
	std::string& msg = val.msg_;
	int32_t fd = val.fd_;
	// 注册proxy
	if (head.msg_id == register_to_proxy)
	{
		CProxyChannel* channel = new CProxyChannel;
		if (channel == NULL)
		{
			LOG_ERROR("default","new CProxyChannel err");
			return;
		}
		channel->Initialize(head.src_server_type, head.src_server_id,  fd);
		CProxyService::GetInstance().AddProxyChannel(head.src_server_type, head.src_server_id, channel);
		LOG_INFO("default","%s, service_id:[%d:%d] regieter succeed!", server_name_map_[head.src_server_type].c_str(), head.src_server_id, fd);
		return;
	}
	else if ( head.send_platform == 1 )
	{
		CPlatformProxyClient::GetInstance().SendMsg(head, msg);
	}
	else
	{
		// 发到本服
		if (head.dst_area_id == GameHostManager::GetInstance().GetServerAreaId())
		{
			CProxyChannel* channel = CProxyService::GetInstance().GetProxyChannel(head.dst_server_type, head.dst_server_id);
			if (channel == NULL)
			{
				LOG_ERROR("default","%s send msg[%d] to %s err, channel is null!", server_name_map_[head.src_server_type].c_str(), head.msg_id, server_name_map_[head.dst_server_type].c_str());
				return;
			}
			uint32_t fd = channel->fd();
			if (fd < 0)
			{
				LOG_ERROR("default","%s send msg[%d] to %s err, channel fd is[%d]", server_name_map_[head.src_server_type].c_str(), head.msg_id, server_name_map_[head.dst_server_type].c_str(), fd);
				return;
			}
			LOG_DEBUG("default","%s send msg[%d] to %s succeed", server_name_map_[head.src_server_type].c_str(), head.msg_id, server_name_map_[head.dst_server_type].c_str());
			CProxyService::GetInstance().client_msg_dispatch(msg, fd, head);
			return;
		}
		// 发到跨服
		else
		{
			CWorldProxyClient::GetInstance().SendMsg(head, msg);
		}
	}
}

int32_t CProxyService::ServerStart()
{
	CPlatformProxyClient::GetInstance().CheckConnect();
	CWorldProxyClient::GetInstance().CheckConnect();
	CPlatformProxyClient::GetInstance().EnableReconnect(2000);
	CWorldProxyClient::GetInstance().EnableReconnect(2000);
	return 0;
}

int main(int argc, char* argv[])
{
#ifdef _MSC_VER
	SetCtrlCHandle(true);
#endif
	int retcode = CProxyService::GetInstance().ServiceMain(argc, argv);
	CProxyService::ReleaseInstance();
#ifdef _MSC_VER
	SetCtrlCHandle(false);
#endif
	return retcode;
}


void CProxyNetChannel::OnMsgEvent()
{
	while (true)
	{

		int32_t msg_id = 0;

		std::string content;

		::common::CProxyHead head;
		bool ret_trans = ::common::CNetMsgTransfer::in_tcp_for_proxy(*this, content, head);

		if (ret_trans == false) {
			return;
		}
		CProxySocketMsg proxy_socket_msg;
		proxy_socket_msg.SetMsg(head, content, fd());
		CProxyService::GetInstance().ProcessServerMsg(proxy_socket_msg);

	}
}

void CProxyNetChannel::OnConnect()
{
	LOG_ERROR("default", "on connect");
}

void CProxyNetChannel::OnDisconnect()
{
	LOG_ERROR("default", "on disconnect");
	CProxyService::GetInstance().del_client_socket(fd());
}
